package com.biovr.backend.security;


import com.biovr.backend.domain.User;
import com.biovr.backend.repository.UserRepository;
import com.biovr.backend.utils.HttpUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * Created by monodev on 2017/6/17.
 */
@Service
public class AuthServiceImpl implements AuthService {

    private AuthenticationManager authenticationManager;
    private UserDetailsService userDetailsService;
    private JwtTokenUtil jwtTokenUtil;
    private UserRepository userRepository;
    private HttpUtils httpUtils;
    @Value("${jwt.tokenHead}")
    private String tokenHead;
    @Autowired
    public AuthServiceImpl(
            AuthenticationManager authenticationManager,
            UserDetailsService userDetailsService,
            JwtTokenUtil jwtTokenUtil,
            UserRepository userRepository,
            HttpUtils httpUtils) {
        this.authenticationManager = authenticationManager;
        this.userDetailsService = userDetailsService;
        this.jwtTokenUtil = jwtTokenUtil;
        this.userRepository = userRepository;
        this.httpUtils = httpUtils;
    }

    /**
     * 注册时将用户密码用BCrypt加密，写入用户角色，由于是开放注册，所以写入角色系统控制，将其写成 ROLE_USER
     * @param userToAdd
     * @return
     */
    @Override
    public User register(User userToAdd) {
        final String username = userToAdd.getUsername();

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        final String rawPassword = userToAdd.getPassword();
        userToAdd.setPassword(encoder.encode(rawPassword));
        userToAdd.setLastPasswordResetDate(new Date());
        userToAdd.setRegisterDate(new Date());
        //userToAdd.setRoles(asList("ROLE_STU"));
        User user= userRepository.insert(userToAdd);
       return user;
    }

    /**
     * 登录时要生成token，完成Spring Security认证，然后返回token给客户端
     * @param username
     * @param password
     * @return
     */
    @Override
    public String login(HttpServletRequest request,String username, String password) {
         String token=null;
        try{
            //生成token
            UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(username, password);
            final Authentication authentication = authenticationManager.authenticate(upToken);
            SecurityContextHolder.getContext().setAuthentication(authentication);
            final UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            token = jwtTokenUtil.generateToken(userDetails);
            //设置登录信息
            User user =userRepository.findByUsername(username);
            user.setLastLogin(new Date());
            user.setLastLoginIp(httpUtils.getIpAddress(request));
            int loginTimes = user.getLoginTimes()+1;
            user.setLoginTimes(loginTimes);
            userRepository.save((user));
        }catch(Exception ex){
    System.out.println(ex);
            token=null;
        }finally {
            return token;
        }



    }

    /**
     * 提供一个可以刷新token的接口 refresh 用于取得新的token
     * @param oldToken
     * @return
     */
    @Override
    public String refresh(String oldToken) {
        final String token = oldToken.substring(tokenHead.length());
        String username = jwtTokenUtil.getUsernameFromToken(token);

        JwtUser user = (JwtUser) userDetailsService.loadUserByUsername(username);
        if (jwtTokenUtil.canTokenBeRefreshed(token, user.getLastPasswordResetDate())){
            return jwtTokenUtil.refreshToken(token);
        }
        return null;
    }
}
